package titt.service.content;

import java.io.OutputStream;

import titt.head.Content;
import titt.head.HTTPHead;
import titt.head.HeadFactory;
import titt.head.response.ResponseHead;
import titt.io.IOFactory;
import titt.io.socket.TITTSocket;
import titt.io.socket.in.TITTInputStream;
import titt.io.socket.out.TITTOutputStream;
import titt.io.util.wrap.AutoWrapper;
import titt.util.ArrayUtil;
import titt.util.io.pipe.PipeListener;

public class NuderResponse implements NuderContent {

	private Object content;
	private TITTInputStream contentStream;

	private int length;
	private boolean complete = false;

	private PipeListener listener;
	private ResponseHead resp;
	
	public NuderResponse(Object content, PipeListener... listeners) {	
		this(content,AutoWrapper.get().getMimeType(content),listeners);
	}
	
	public NuderResponse(Object content, String contentType, PipeListener... listeners) {
		this(content,200,contentType,listeners);
	}

	public NuderResponse(Object content, int status, PipeListener... listeners) {
		this(content,status,AutoWrapper.get().getMimeType(content),listeners);
	}
	
	public NuderResponse(Object content, int status, String contentType, PipeListener... listeners) {
		this(content,status,contentType,HeadFactory.EMPTY,listeners);
	}
	
	public NuderResponse(Object content, int status, String contentType, HTTPHead head, PipeListener... listeners) {
		Content c = new Content(AutoWrapper.get().getLength(content), contentType, head);
		this.resp = new ResponseHead(status, c);
		this.length = c.getContentLength();
		this.content = content;
		this.listener = IOFactory.createListener(listeners);
	}
	
	NuderResponse(ResponseHead resp, TITTInputStream in) {
		Content c = new Content(resp);
		this.resp = resp;
		this.contentStream = in;
		this.content = in;
		this.length = c.containsContentLength()? c.getContentLength() : -1;
	}

	
	
	@SuppressWarnings("unchecked")
	@Override
	public <T> T getContentObject() {
		return (T)content;
	}

	@Override
	public TITTInputStream getContentStream() {
		return contentStream;
	}

	@Override
	public int getLength() {
		return length;
	}

	@Override
	public synchronized void waitForCompletion() {
		while(!complete) 
			try {	
				wait();
			}
			catch(Exception e) {}
	}

	@Override
	public void writeToStream(OutputStream out, PipeListener... listeners) throws Exception {
		writeToStream(IOFactory.createOutputStream(out), listeners);
	}

	@Override
	public synchronized void writeToStream(final TITTOutputStream out, PipeListener... listeners) throws Exception {
		PipeListener pl = IOFactory.createInternalNuderListener(out, contentStream, listener != null? ArrayUtil.combine(new PipeListener[]{listener}, listeners) : listeners);
		
		if(contentStream == null)
			AutoWrapper.get().writeTo(pl, out, content);
		else 
			try {
				IOFactory.createStreamPiper().pipe(contentStream, out, length, pl);
			}
			catch(Exception e) {
				contentStream.close();
				throw e;
			}

		out.flush();
		
		contentStream.close();

		complete = true;
		notifyAll();
	}
	
	void encodeAndWriteToSocket(TITTSocket s) throws Exception {
		s.getHeadWriter().writeHead(getResponseHead());
		writeToStream(s.getOutputStream());
	}
	
	public ResponseHead getResponseHead() {
		return resp;
	}

}
